#pragma once
#include "../common/dispatcher.hpp"
#include "requestor.hpp"
#include "rpc_caller.hpp"
#include "rpc_registry.hpp"
#include "rpc_topic.hpp"

//基础Rpc功能
//服务注册功能
//服务发现功能
//基层网络通信模块
namespace rpc
{
    namespace client
    {
        //服务注册客户端->应用于服务提供者向注册中心进行服务注册
        class RegistryClient
        {
        public:
            using ptr = std::shared_ptr<RegistryClient>;
            RegistryClient(const std::string & ip,int port)://注册中心的地址信息->用于连接注册中心
            _requestor(std::make_shared<Requestor>()),
            _provider(std::make_shared<client::Provider>(_requestor)),
            _dispatcher(std::make_shared<Dispatcher>())
            {
                auto rsp_cb = std::bind(&client::Requestor::onResponse,_requestor.get(),std::placeholders::_1,std::placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_SERVICE,rsp_cb);
                auto message_cb = std::bind(&Dispatcher::onMessage,_dispatcher.get(),std::placeholders::_1,std::placeholders::_2);
                _client = ClientFactory::create(ip,port);
                _client->setMessageCallback(message_cb);
                _client->connect();
            }

            //提供服务注册方法
            bool registryMethod(const std::string & method,const Address & host)
            {
                return _provider->registryMethod(_client->connection(),method,host);
            }
        private:
            Requestor::ptr _requestor;//通信消息管理模块
            client::Provider::ptr _provider;//进行服务注册
            Dispatcher::ptr _dispatcher;//消息的分发
            BaseClient::ptr _client;//连接对象
        };

        //服务发现客户端->引用于服务调用者进行向注册中心进行服务发现
        class DiscoveryClient
        {
        public:
            using ptr = std::shared_ptr<DiscoveryClient>;
            DiscoveryClient(const std::string & ip,int port,const Discoverer::OfflineCallback & cb):
            _requestor(std::make_shared<Requestor>()),_discoverer(std::make_shared<client::Discoverer>(_requestor,cb)),
            _dispatcher(std::make_shared<Dispatcher>())
            {
                auto rsp_cb = std::bind(&client::Requestor::onResponse,_requestor.get(),std::placeholders::_1,std::placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_SERVICE,rsp_cb);
                auto req_cb = std::bind(&client::Discoverer::onServiceRequest,_discoverer.get(),std::placeholders::_1,std::placeholders::_2);
                _dispatcher->registerHandler<ServiceRequest>(MType::REQ_SERVICE,req_cb);
                auto message_cb = std::bind(&Dispatcher::onMessage,_dispatcher.get(),std::placeholders::_1,std::placeholders::_2);
                _client = ClientFactory::create(ip,port);
                _client->setMessageCallback(message_cb);
                _client->connect();
            }

            //服务发现方法
            bool serviceDiscovery(const std::string & method,Address & host)
            {
                return _discoverer->serviceDiscovery(_client->connection(),method,host);
            }
        private:
            Requestor::ptr _requestor;
            client::Discoverer::ptr _discoverer;//服务发现者
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;
        };

        //Rpc客户端->业务客户端->提供基础的Rpc客户端和服务发现功能的Rpc客户端
        class RpcClient
        {
        public:
            using ptr = std::shared_ptr<RpcClient>;
            //是否启用服务发现功能->决定后面的是注册中心的地址还是服务提供者的地址
            RpcClient(bool enableDiscovery,const std::string & ip,int port):
            _enableDiscovery(enableDiscovery),
            _requestor(std::make_shared<Requestor>()),
            _dispatcher(std::make_shared<Dispatcher>()),
            _caller(std::make_shared<rpc::client::RpcCaller>(_requestor))
            {
                //针对Rpc请求后的响应进行处理
                auto rsp_cb = std::bind(&client::Requestor::onResponse,_requestor.get(),std::placeholders::_1,std::placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_RPC,rsp_cb);
                if(_enableDiscovery)
                {
                    //如果启用了服务发现,地址是注册中心的地址,是服务发现客户端需要连接的地址,则通过地址信息实例化discovery_client   
                    auto offline_cb = std::bind(&RpcClient::delClient,this,std::placeholders::_1);
                    _discovery_client = std::make_shared<DiscoveryClient>(ip,port,offline_cb);
                }
                else
                {
                    //如果没有启用服务发现,则地址信息是服务提供者的地址,则直接实例化客户端
                    auto message_cb = std::bind(&Dispatcher::onMessage,_dispatcher.get(),std::placeholders::_1,std::placeholders::_2);
                    _rpc_client = ClientFactory::create(ip,port);
                    _rpc_client->setMessageCallback(message_cb);
                    _rpc_client->connect();
                }
            }

            //同步调用
            bool call(const std::string & method,const Json::Value & params,Json::Value & result)
            {
                
                BaseClient::ptr client = getClient(method);
                if(client.get() == nullptr)
                {
                    return false;
                }
                return _caller->call(client->connection(),method,params,result);
            }

            //异步调用
            bool call(const std::string & method,const Json::Value & params,RpcCaller::JsonAsyncResponse & result)
            {
                BaseClient::ptr client = getClient(method);
                if(client.get() == nullptr)
                {
                    return false;
                }
                return _caller->call(client->connection(),method,params,result);
            }

            //回调函数调用
            bool call(const std::string & method,const Json::Value & params,const RpcCaller::JsonResponseCallback & cb)
            {
                BaseClient::ptr client = getClient(method);
                if(client.get() == nullptr)
                {
                    return false;
                }
                return _caller->call(client->connection(),method,params,cb);
            }
        private:
            //对_rpc_clients的相关方法封装
            //创建新的客户端
            BaseClient::ptr newClient(const Address & host)
            {
                auto message_cb = std::bind(&Dispatcher::onMessage,_dispatcher.get(),std::placeholders::_1,std::placeholders::_2);
                auto client = ClientFactory::create(host.first,host.second);
                client->setMessageCallback(message_cb);
                client->connect();
                putClient(host,client);
                return client;
            }

            //获取一个客户端对象
            BaseClient::ptr getClient(const Address & host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _rpc_clients.find(host);
                if(it == _rpc_clients.end())
                {
                    return BaseClient::ptr();
                }
                return it->second;
            }

            //获取服务提供者(服务发现,固定的服务提供者)
            BaseClient::ptr getClient(const std::string & method)
            {
                BaseClient::ptr client;
                if(_enableDiscovery)
                {
                    //服务发现
                    Address host;
                    bool ret = _discovery_client->serviceDiscovery(method,host);
                    if(ret == false)
                    {
                        LOG(ERROR,"当前 %s 服务,没有找到服务提供者",method.c_str());
                        return BaseClient::ptr();
                    }
                    //获取到地址信息
                    client = getClient(host);
                    if(client.get() == nullptr)
                    {
                        client = newClient(host);
                    }
                }
                else
                {
                    //固定的客户端
                    client = _rpc_client;
                }
                return client;
            }

            //新增地址信息
            void putClient(const Address & host,BaseClient::ptr & client)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _rpc_clients.insert(std::make_pair(host,client));
            }

            //删除客户端信息->服务下线进行删除
            void delClient(const Address & host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _rpc_clients.erase(host);
            }

        private:

            //自定义类型进行hash映射
            struct AddressHash
            {
                size_t operator()(const Address & host) const
                {
                    std::string addr = host.first+std::to_string(host.second);
                    return std::hash<std::string>{}(addr);//{}初始化一个类模板对象
                }
            };
            bool _enableDiscovery;//是否启用服务发现功能
            DiscoveryClient::ptr _discovery_client;//发现客户端->先进行发现再进行Rpc调用
            Requestor::ptr _requestor;
            RpcCaller::ptr _caller;//Rpc调用功能
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _rpc_client;//用于未启动服务发现,直接使用的客户端
            std::mutex _mutex;
            //用于启用服务发现,保存客户端连接池
            //选择使用长连接:地址信息和客户端->通过_discovery_client进行查找地址信息
            std::unordered_map<Address,BaseClient::ptr,AddressHash> _rpc_clients;//短连接->异步调用则需要选择合适的地方进行关闭客户端
        };

        //主题客户端
        class TopicClient
        {
        public:
            TopicClient(const std::string & ip,int port):
            _requestor(std::make_shared<Requestor>()),
            _dispatcher(std::make_shared<Dispatcher>()),
            _topic_manager(std::make_shared<TopicManager>(_requestor))
            {
                auto rsp_cb = std::bind(&Requestor::onResponse,_requestor.get(),std::placeholders::_1,std::placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_TOPIC,rsp_cb);
                auto msg_cb = std::bind(&TopicManager::onPublish,_topic_manager.get(),std::placeholders::_1,std::placeholders::_2);
                _dispatcher->registerHandler<TopicRequest>(MType::REQ_TOPIC,msg_cb);//服务器广播请求处理回调函数
                auto message_cb = std::bind(&Dispatcher::onMessage,_dispatcher.get(),std::placeholders::_1,std::placeholders::_2);
                _rpc_client = ClientFactory::create(ip,port);
                _rpc_client->setMessageCallback(message_cb);
                _rpc_client->connect();

            }

            //主题创建
            bool create(const std::string & key)
            {
                return _topic_manager->create(_rpc_client->connection(),key);
            }

            //主题删除
            bool remove(const std::string & key)
            {
                return _topic_manager->remove(_rpc_client->connection(),key);
            }

            //主题订阅
            bool subscribe(const std::string & key,const TopicManager::SubCallback & cb)
            {
                return _topic_manager->subscribe(_rpc_client->connection(),key,cb);
            }

            //取消订阅
            bool cancel(const std::string & key)
            {
                return _topic_manager->cancel(_rpc_client->connection(),key);
            }

            //发布消息
            bool publish(const std::string & key,const std::string & msg)
            {
                return _topic_manager->publish(_rpc_client->connection(),key,msg);
            }

            //关闭连接
            void shutdown()
            {
                _rpc_client->shutdown();
            }
            
        private:
            Requestor::ptr _requestor;
            TopicManager::ptr _topic_manager;//主题管理
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _rpc_client;
        };

    }
}